﻿using System.Collections.Generic;
using System;
using BCService.Utils;
using BCCommon;
using BCDto.TMS.LearnTrain.VehicleTrainingScheduleRecord;
using BCEntity.TMS.LearningTrain.VehicleTrainingScheduleRecord;
using BCDto.Sim.Admin.Admin;
using BCDto.TMS.LearnTrain.VehicleTrainingScheduleRecord.TrainingScheduleRecordRequest;
using BCData.TMS.TrainingSite.TrainingSiteConfig;
using BCEntity.Common.EntityNameConst;
using BCData.TMS.LearningTrain;
using BCData.TMS.NotificationMessageRecord;
using BCEntity.TMS.NotificationMessageRecord;
using BCCommon.Enums;
using BCData.TMS.Driver;
using BCService.Common.PushMessage.PushMessageSend;

namespace BCService.TMS.LearningTrain
{
    public class VehicleTrainingScheduleRecordService : IVehicleTrainingScheduleRecordService
    {

        private readonly IDatabaseContext databaseContext;
        private readonly IVehicleTrainingScheduleRecordData vehicleTrainingScheduleRecordData;
        private readonly ITrainingSiteConfigData trainingSiteConfigData;
        private readonly IPendingLearningVehicleData pendingLearningVehicleData;
        private readonly IRedisService redisService;
        private readonly INotificationMessageRecordData notificationMessageRecordData;
        private readonly IDriverData driverData;
        private readonly IPushMessageSendService pushMessageSendService;
        private readonly string keyPendingLearningVehicle = string.Format("{0}", EntityNameConst.PendingLearningVehicleEntity);
        private readonly string keyVehicleTrainingScheduleRecord = string.Format("{0}", EntityNameConst.VehicleTrainingScheduleRecordEntity);
        public VehicleTrainingScheduleRecordService(IVehicleTrainingScheduleRecordData vehicleTrainingScheduleRecordData,
            IDatabaseContext databaseContext,
            ITrainingSiteConfigData trainingSiteConfigData,
            IPendingLearningVehicleData pendingLearningVehicleData,
            IRedisService redisService,
            INotificationMessageRecordData notificationMessageRecordData,
            IDriverData driverData,
            IPushMessageSendService pushMessageSendService)
        {
            this.vehicleTrainingScheduleRecordData = vehicleTrainingScheduleRecordData;
            this.databaseContext = databaseContext;
            this.trainingSiteConfigData = trainingSiteConfigData;
            this.pendingLearningVehicleData = pendingLearningVehicleData;
            this.redisService = redisService;
            this.notificationMessageRecordData = notificationMessageRecordData;
            this.driverData = driverData;
            this.pushMessageSendService = pushMessageSendService;
        }


        /// <summary>
        /// 添加新VehicleTrainingScheduleRecord纪录
        /// </summary>
        /// <param name="requestDto">培训期数信息</param>
        /// <param name="admin">管理员信息</param>
        /// <returns></returns>
        public VehicleTrainingScheduleRecordDto Add(AdminDto admin, VehicleTrainingScheduleRecordRequestDto requestDto)
        {
            if (admin.AgentRecord==null)
            {
                throw new ArgumentException(" 用户验证失败,错误操作 ");
            }
            if (requestDto.TrainingStartDate > requestDto.TrainingEndDate)
            {
                throw new ArgumentException(" 培训结束时间不可小于开始时间 ");
            }
            foreach (var item in requestDto.PendingLearningVehicleIds)
            {
                var tempPendingLearningVehicleEntity = this.pendingLearningVehicleData.GetEntityAsync(item).Result;
                if (tempPendingLearningVehicleEntity == null)
                {
                    throw new ArgumentException(" 待培训司机不存在 ");
                }
                var driver = this.driverData.GetDriverByIdAsync(tempPendingLearningVehicleEntity.DriverId).Result;
                if (driver == null)
                {
                    throw new ArgumentException(" 当前选中的司机不存在 ");
                }
                if (tempPendingLearningVehicleEntity.IsAbsenteeism)
                {
                    continue;
                }
                if (tempPendingLearningVehicleEntity.VehicleTrainingScheduleRecordId.HasValue)
                {
                    var tempVehicleTrainingScheduleRecord = this.vehicleTrainingScheduleRecordData.GetEntityAsync(tempPendingLearningVehicleEntity.VehicleTrainingScheduleRecordId.Value).Result;
                    if (tempVehicleTrainingScheduleRecord != null && tempVehicleTrainingScheduleRecord.TrainingEndDate < DateTime.Now.AddDays(1).Date)//参加过培训
                    {

                        throw new ArgumentException("当前手机号为" + driver.Phone + "的" + driver.Name + "司机已被安排培训,不可重复安排,如有必要,请去设置补考");
                    }
                }
            }
            var trainingSiteConfigEntity = this.trainingSiteConfigData.GetEntity(requestDto.TrainingSiteConfigId).Result;
            if (trainingSiteConfigEntity==null)
            {
                throw new ArgumentException(" 培训点不存在,添加培训记录错误 ");
            }
            if (trainingSiteConfigEntity.AgentRecordId!=admin.AgentRecord.AgentRecordId)
            {
                throw new ArgumentException(" 不可操作别人的培训点 ");
            }
            if (trainingSiteConfigEntity.AppointmentAvailable < requestDto.PendingLearningVehicleIds.Count)
            {
                throw new ArgumentException(" 培训人数大于当前培训点的可预约人数,参加培训失败 ");
            }

            var entity = new VehicleTrainingScheduleRecordEntity()
            {
                AgentRecordId = admin.AgentRecord.AgentRecordId,
                TrainingSiteConfigId = trainingSiteConfigEntity.TrainingSiteConfigId,
                TrainingSiteName = trainingSiteConfigEntity.TrainingSiteName?.Trim(),
                TrainingSiteAddress = trainingSiteConfigEntity.TrainingSiteAddress?.Trim(),
                AppointmentAvailable = trainingSiteConfigEntity.AppointmentAvailable,
                TrainingTitle = requestDto.TrainingTitle?.Trim(),
                TrainingStartDate = requestDto.TrainingStartDate,
                TrainingEndDate = requestDto.TrainingEndDate,
                TrainingTeacher = requestDto.TrainingTeacher?.Trim(),
                CreateTime = DateTime.Now,
                EditerId = admin.AdminId,
                Editer = admin.FullName,
            };

            entity.TrainingPeriods = trainingSiteConfigEntity.TrainingSiteName+ " - 第" + entity.TrainingStartDate.ToString("yyyyMMdd") + "期";
            var isExist = this.vehicleTrainingScheduleRecordData.IsExist(entity.TrainingPeriods, admin.AgentRecord.AgentRecordId,
                trainingSiteConfigEntity.TrainingSiteConfigId).GetAwaiter().GetResult();
            if (isExist)
            {
                throw new ArgumentException(entity.TrainingPeriods + "的培训已存在，请重试");
            }
            this.databaseContext.BeginTransaction();
            var result = this.vehicleTrainingScheduleRecordData.InsertAsync(entity).GetAwaiter().GetResult();//添加培训计划
            foreach (var item in requestDto.PendingLearningVehicleIds)
            {
                var pendingLearningTrainEntity = this.pendingLearningVehicleData.GetEntityAsync(item).Result;
                if (pendingLearningTrainEntity == null)
                {
                    throw new ArgumentException(" 获取司机待培训信息失败,不可添加培训 ");
                }
                pendingLearningTrainEntity.IsAbsenteeism = false;
                pendingLearningTrainEntity.IsNotifyPayment = true;
                pendingLearningTrainEntity.NotifyTime = DateTime.Now;
                pendingLearningTrainEntity.VehicleTrainingScheduleRecordId = result.VehicleTrainingScheduleRecordId;
                this.pendingLearningVehicleData.UpdateAsync(pendingLearningTrainEntity).GetAwaiter().GetResult();
            }
            this.databaseContext.Commit();
            //发通知
            this.CreateVehicleServiceNotification(requestDto.PendingLearningVehicleIds, result);
            this.redisService.DeleteMultipleKey(keyVehicleTrainingScheduleRecord, false);
            this.redisService.DeleteMultipleKey(keyPendingLearningVehicle, false);
            return result.As<VehicleTrainingScheduleRecordDto>();
        }

        public VehicleTrainingScheduleRecordDto TwiceAddVehicleTrainingScheduleRecord(AdminDto admin, long vehicleTrainingScheduleRecordId,
            VehicleTrainingScheduleRecordPutDto putDto)
        {
            if (admin.AgentRecord == null)
            {
                throw new ArgumentException(" 用户认证失败,错误操作 ");
            }
            var vehicleTrainingScheduleRecordEntity = this.vehicleTrainingScheduleRecordData.GetEntityAsync(vehicleTrainingScheduleRecordId).GetAwaiter().GetResult();
            if (vehicleTrainingScheduleRecordEntity == null)
            {
                throw new ArgumentException("培训计划不存在,请重新选择");
            }
            var pendingCount = this.pendingLearningVehicleData.GetCount(vehicleTrainingScheduleRecordId).Result;
            if (pendingCount + putDto.PendingLearningVehicleIds.Count > vehicleTrainingScheduleRecordEntity.AppointmentAvailable)
            {
                throw new ArgumentException(" 培训人数大于培训点的总预约人数,请重新选择司机 ");
            }
            foreach (var item in putDto.PendingLearningVehicleIds)
            {
                var tempPendingLearningVehicleEntity = this.pendingLearningVehicleData.GetEntityAsync(item).Result;
                if (tempPendingLearningVehicleEntity == null)
                {
                    throw new ArgumentException(" 待培训司机不存在 ");
                }
                var driver = this.driverData.GetDriverByIdAsync(tempPendingLearningVehicleEntity.DriverId).Result;
                if (driver == null)
                {
                    throw new ArgumentException(" 当前选中的司机不存在 ");
                }
                if (tempPendingLearningVehicleEntity.IsAbsenteeism)
                {
                    continue;
                }
                if (tempPendingLearningVehicleEntity.VehicleTrainingScheduleRecordId.HasValue)
                {
                    var tempVehicleTrainingScheduleRecord = this.vehicleTrainingScheduleRecordData.GetEntityAsync(tempPendingLearningVehicleEntity.VehicleTrainingScheduleRecordId.Value).Result;
                    if (tempVehicleTrainingScheduleRecord != null && 
                        tempVehicleTrainingScheduleRecord.TrainingEndDate < DateTime.Now.AddDays(1).Date
                        && !tempPendingLearningVehicleEntity.IsAbsenteeism)//参加过培训
                    {

                        throw new ArgumentException("当前手机号为" + driver.Phone + "的" + driver.Name + "司机已被安排培训,不可重复安排,如有必要,请去设置补考");
                    }
                }
            }
            this.databaseContext.BeginTransaction();
            foreach (var item in putDto.PendingLearningVehicleIds)
            {
                var pendingLearningTrainEntity = this.pendingLearningVehicleData.GetEntityAsync(item).Result;
                if (pendingLearningTrainEntity == null)
                {
                    throw new ArgumentException(" 获取司机待培训信息失败,不可添加培训 ");
                }
                if (pendingLearningTrainEntity.VehicleTrainingScheduleRecordId.HasValue&&!pendingLearningTrainEntity.IsAbsenteeism)
                {
                    throw new ArgumentException(" 选择的司机中存在已预约的司机,不可重新预约培训 ");
                }
                pendingLearningTrainEntity.IsAbsenteeism = false;
                pendingLearningTrainEntity.IsNotifyPayment = true;
                pendingLearningTrainEntity.NotifyTime = DateTime.Now;
                pendingLearningTrainEntity.VehicleTrainingScheduleRecordId = vehicleTrainingScheduleRecordEntity.VehicleTrainingScheduleRecordId;
                this.pendingLearningVehicleData.UpdateAsync(pendingLearningTrainEntity).GetAwaiter().GetResult();
            }
            this.databaseContext.Commit();
            //发通知
            this.CreateVehicleServiceNotification(putDto.PendingLearningVehicleIds, vehicleTrainingScheduleRecordEntity);
            this.redisService.DeleteMultipleKey(keyVehicleTrainingScheduleRecord, false);
            this.redisService.DeleteMultipleKey(keyPendingLearningVehicle, false);
            return vehicleTrainingScheduleRecordEntity.As<VehicleTrainingScheduleRecordDto>();
        }

        /// <summary>
        /// 发通知
        /// </summary>
        /// <param name="pendingLearningVehicleIds">待培训编号</param>
        /// <param name="result"></param>
        private void CreateVehicleServiceNotification(List<long> pendingLearningVehicleIds, VehicleTrainingScheduleRecordEntity result)
        {
            foreach (var item in pendingLearningVehicleIds)
            {
                //增加车辆服务培训通知记录
                var pendingLearningVehicle = this.pendingLearningVehicleData.GetEntityAsync(item).GetAwaiter().GetResult();//获取待培训的信息
                if (pendingLearningVehicle==null)
                {
                    continue;
                }
                var driverEntity = this.driverData.GetDriverByIdAsync(pendingLearningVehicle.DriverId).Result;
                if (driverEntity == null)
                {
                    continue;
                }
                var notification = new NotificationMessageRecordEntity()
                {
                    NotificationTitle = "司机培训",
                    NotificationContent = $"尊敬的司机：请您于{result.TrainingStartDate.Date.ToString("yyyy-MM-dd")}至{result.TrainingEndDate.Date.ToString("yyyy-MM-dd")}时间段，参加公司组织的集体培训。",
                    NotificationType = NotificationMessageRecordType.Message.ToString(),
                    CreateTime = DateTime.Now,
                    RelatedRecordId = item,
                    UserId = driverEntity.UserId,
                };
                this.notificationMessageRecordData.InsertAsync(notification).GetAwaiter().GetResult();
                //var vehicleServiceNotificationRecordEntity = new VehicleServiceNotificationRecordEntity
                //{
                //    DriverId = pendingLearningVehicle.DriverId,
                //    CompanyId = pendingLearningVehicle.CompanyId,
                //    PartnerId = pendingLearningVehicle.PartnerId,
                //    VehicleId = pendingLearningVehicle.VehicleId,
                //    NotificationType = VehicleManageFeeNotificationType.Message.ToString(),
                //    NotificationTypeName = VehicleManageFeeNotificationType.Message.GetDescriptionString(),
                //    NotificationContent = $"尊敬的司机：请您于{result.TrainingStartDate.Date.ToString("yyyy-MM-dd")}至{result.TrainingEndDate.Date.ToString("yyyy-MM-dd")}时间段，参加公司组织的集体培训。",
                //    PendingLearningVehicleId = pendingLearningVehicle.pendingLearningVehicleId,
                //    VehicleServiceNotificationOrderCode = Guid.NewGuid().ToString(),
                //    NotificationTitle = result.TrainingTitle
                //};
                //var insertResult = vehicleServiceNotificationRecordData.InsertAsync(vehicleServiceNotificationRecordEntity).GetAwaiter().GetResult();//添加通知
                this.pushMessageSendService.PushMessageForDriverTrain(new long[] { driverEntity.UserId }, 
                    PushMessageType.DriverTrainingScheduleNotification, result.TrainingStartDate.Date, result.TrainingEndDate.Date);//推送信息
            }
        }

        public PageableList<VehicleTrainingScheduleRecordViewDto> GetTrainRecord(AdminDto admin, long? trainingSiteConfigId, DateTime? trainDate,
            int pageIndex, int pageSize)
        {
            long? agentRecordId = null;
            if (admin.AgentRecord!=null)
            {
                agentRecordId = admin.AgentRecord.AgentRecordId;
            }
            string cacheKey = this.redisService.GetKey(keyVehicleTrainingScheduleRecord, agentRecordId, trainingSiteConfigId, trainDate,
             pageIndex, pageSize);
            var resultRedis = this.redisService.TryGet(cacheKey, () =>
            {
                var (list, count) = this.vehicleTrainingScheduleRecordData.Query(agentRecordId, trainingSiteConfigId, trainDate,
                 pageIndex, pageSize).GetAwaiter().GetResult();
                return new PageableList<VehicleTrainingScheduleRecordViewDto>()
                {
                    Items = list.As<IEnumerable<VehicleTrainingScheduleRecordViewDto>>(),
                    Count = count,
                    PageIndex = pageIndex,
                    PageSize = pageSize,
                    ServerTime = DateTime.Now,
                };
            }, TimeSpan.FromDays(1));
            return resultRedis;
        }

        public IEnumerable<VehicleTrainingScheduleRecordDto> GetTwicePendingRecord(AdminDto admin, DateTime? Date)
        {
            if (admin.AgentRecord == null)
            {
                throw new ArgumentException(" 用户认证失败,错误操作 ");
            }
            string cacheKey = this.redisService.GetKey(keyVehicleTrainingScheduleRecord, admin.AgentRecord.AgentRecordId, Date);
            var resultRedis = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.vehicleTrainingScheduleRecordData.GetTwicePendingRecord(admin.AgentRecord.AgentRecordId, Date).GetAwaiter().GetResult();
                return data.As<List<VehicleTrainingScheduleRecordDto>>();
            }, TimeSpan.FromDays(1));
            return resultRedis;

        }
    }
}